package cn.mulanbay.message.handler;

import cn.mulanbay.business.bean.SysMessageBean;
import cn.mulanbay.business.cache.YcCache;
import cn.mulanbay.business.handler.BaseHandler;
import cn.mulanbay.business.handler.CacheHandler;
import cn.mulanbay.common.config.CacheKey;
import cn.mulanbay.common.exception.ErrorCode;
import cn.mulanbay.common.util.BeanFactoryUtil;
import cn.mulanbay.common.util.DateUtil;
import cn.mulanbay.common.util.StringUtil;
import cn.mulanbay.message.persistent.service.SystemMonitorUserService;
import cn.mulanbay.message.persistent.service.UserMessageService;
import cn.mulanbay.persistent.entity.ErrorCodeDefine;
import cn.mulanbay.persistent.entity.SystemMonitorUser;
import cn.mulanbay.persistent.entity.UserMessage;
import cn.mulanbay.persistent.enums.MessageSendStatus;
import cn.mulanbay.persistent.enums.MessageSource;
import cn.mulanbay.persistent.enums.MessageType;
import cn.mulanbay.persistent.enums.MonitorBussType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

@RefreshScope
@Component
public class MessageNotifyHandler extends BaseHandler {

    private static final Logger logger = LoggerFactory.getLogger(MessageNotifyHandler.class);

    @Value("${notify.message.expectSendTime:09:00}")
    String defaultExpectSendTime;

    @Value("${notify.message.send:false}")
    boolean send;

    @Autowired
    UserMessageService userMessageService;

    @Autowired
    CacheHandler cacheHandler;

    @Autowired
    SystemMonitorUserService systemMonitorUserService;

    @Autowired
    RedisDelayQueueHandler redisDelayQueueHandler;

    public MessageNotifyHandler() {
        super("消息提醒");
    }

    /**
     * 添加通知消息
     *
     * @param message
     */
    public void addNotifyMessage(UserMessage message) {
        userMessageService.save(message);
        if(!send){
            return;
        }
        //加入到最新的一条消息(两小时有效)
        String key = CacheKey.getKey(CacheKey.USER_LATEST_MESSAGE, message.getUserId().toString());
        cacheHandler.set(key, message, 7200);
        redisDelayQueueHandler.addMessage(message);
    }

    /**
     * 向系统中需要通知的人发送系统消息
     * 消息只针对管理员，所以这里发送的都是系统消息
     * @param smb
     */
    public void addMessageToNotifier(SysMessageBean smb) {
        try {
            ErrorCodeDefine ec = this.getErrorCodeDefine(smb.getCode());
            //获取发送时间
            LocalDateTime expectSendTime = this.getExpectSendTime(ec, smb.getExpectSendTime());
            if (expectSendTime == null) {
                return;
            }
            // spring aop对于内部方法调用失效，需要进行bean外层调用
            List<SystemMonitorUser> userList = BeanFactoryUtil.getBean(this.getClass()).getMonitorUsers(ec.getBussType());
            if (StringUtil.isEmpty(userList)) {
                logger.warn("业务类型[" + ec.getBussType().getName() + "]没有配置系统监控人员");
                return;
            }
            String title = smb.getTitle();
            title += "(code=" + smb.getCode() + ")";
            for (SystemMonitorUser smu : userList) {
                //限流判断
                boolean check = this.checkErrorCodeLimit(ec, smu.getUserId());
                if (check) {
                    UserMessage ssm = this.createUserMessage(ec, smu.getUserId(), expectSendTime, title, smb.getContent(), null, smb.getRemark());
                    this.addNotifyMessage(ssm);
                } else {
                    logger.debug("code[" + ec.getCode() + "],userId[" + smu.getUserId() + "]触发限流，不发送");
                }
            }
        } catch (Exception e) {
            logger.error("发送系统消息异常", e);
        }
    }

    private UserMessage createUserMessage(ErrorCodeDefine ec, Long userId, LocalDateTime expectSendTime, String title, String content, String url, String remark) {
        UserMessage message = new UserMessage();
        message.setExpectSendTime(expectSendTime);
        message.setUserId(userId);
        message.setContent(content);
        message.setCreatedTime(LocalDateTime.now());
        message.setFailCount(0);
        message.setCode(ec.getCode());
        //没有作用
        message.setMessageType(MessageType.WX);
        message.setSource(MessageSource.OP);
        message.setBussType(ec.getBussType());
        message.setLogLevel(ec.getLevel());
        message.setTitle(title);
        message.setUrl(url);
        message.setRemark(remark);
        message.setSendStatus(MessageSendStatus.UN_SEND);
        return message;
    }


    /**
     * 检查错误代码限流发送
     *
     * @param ec
     * @param userId
     * @return
     */
    private boolean checkErrorCodeLimit(ErrorCodeDefine ec, Long userId) {
        if (ec.getLimitPeriod() <= 0) {
            return true;
        } else {
            String key = CacheKey.getKey(CacheKey.USER_ERROR_CODE_LIMIT, userId.toString(), ec.getCode().toString());
            Integer n = cacheHandler.get(key, Integer.class);
            if (n == null) {
                cacheHandler.set(key, 0, ec.getLimitPeriod());
                return true;
            } else {
                //不通过，不用再发
                return false;
            }
        }
    }

    /**
     * 获取提醒时间
     *
     * @param ec
     * @param notifyTime
     * @return
     */
    private LocalDateTime getExpectSendTime(ErrorCodeDefine ec, LocalDateTime notifyTime) {
        if (!ec.getNotifiable()) {
            logger.warn("代码[" + ec.getCode() + "]配置为不发送消息");
            return null;
        }
        if (notifyTime == null) {
            //由代码配置决定
            if (ec.getRealtimeNotify()) {
                notifyTime = LocalDateTime.now();
            } else {
                //统一一个时间发送
                Date dd = DateUtil.getDate(DateUtil.getToday() + " " + defaultExpectSendTime + ":00", DateUtil.Format24Datetime);
                notifyTime = DateUtil.date2LocalDateTime(dd);
            }
        }
        return notifyTime;
    }

    @YcCache(key = "'systemMonitorUsers:'+ #bussType")
    public List<SystemMonitorUser> getMonitorUsers(MonitorBussType bussType){
        return systemMonitorUserService.getListByBussType(bussType);
    }

    /**
     * 获取错误代码定义
     * @param code
     * @return
     */
    private ErrorCodeDefine getErrorCodeDefine(Integer code){
        ErrorCodeDefine ecd = userMessageService.getErrorCodeDefine(code);
        if (ecd == null) {
            ecd = userMessageService.getErrorCodeDefine(ErrorCode.COMMON_CODE);
        }
        return ecd;
    }
}
